//=============================================================================
//                                                                            
//                               OpenMesh                                     
//      Copyright (C) 2001-2005 by Computer Graphics Group, RWTH Aachen       
//                           www.openmesh.org                                 
//                                                                            
//-----------------------------------------------------------------------------
//                                                                            
//                                License                                     
//                                                                            
//   This library is free software; you can redistribute it and/or modify it 
//   under the terms of the GNU Library General Public License as published  
//   by the Free Software Foundation, version 2.                             
//                                                                             
//   This library is distributed in the hope that it will be useful, but       
//   WITHOUT ANY WARRANTY; without even the implied warranty of                
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         
//   Library General Public License for more details.                          
//                                                                            
//   You should have received a copy of the GNU Library General Public         
//   License along with this library; if not, write to the Free Software       
//   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 
//                                                                            
//-----------------------------------------------------------------------------
//                                                                            
//   $Revision: 1.3 $
//   $Date: 2005-12-21 13:55:21 $
//                                                                            
//=============================================================================

/** \file ModProgMeshT.cc
*/


//=============================================================================
//
//  CLASS ModProgMeshT - IMPLEMENTATION
//
//=============================================================================

#define OPENMESH_DECIMATER_MODPROGMESH_CC


//== INCLUDES =================================================================

#include <vector>
#include <fstream>
// --------------------
#include <Core/Utils/vector_cast.hh>
#include <Core/IO/BinaryHelper.hh>
#include <Core/Utils/Endian.hh>
// --------------------
#include <Tools/Decimater/ModProgMeshT.hh>


//== NAMESPACE =============================================================== 

namespace OpenMesh  {
	namespace Decimater {



		//== IMPLEMENTATION ========================================================== 


		template <class DecimaterType>
		bool 
			ModProgMeshT<DecimaterType>::
			write( const std::string& _ofname )
		{
			// sort vertices
			size_t i=0, N=Self::mesh().n_vertices(), n_base_vertices(0), n_base_faces(0);
			std::vector<typename Mesh::VertexHandle>  vhandles(N);


			// base vertices
			typename Mesh::VertexIter 
				v_it=Self::mesh().vertices_begin(), 
				v_end=Self::mesh().vertices_end();

			for (; v_it != v_end; ++v_it)  
				if (!Self::mesh().status(v_it).deleted()) 
				{
					vhandles[i] = v_it.handle();  
					Self::mesh().property( idx_, v_it ) = i;  
					++i;
				}
				n_base_vertices = i;


				// deleted vertices
				typename InfoList::reverse_iterator
					r_it=pmi_.rbegin(), r_end=pmi_.rend();

				for (; r_it!=r_end; ++r_it)  
				{ 
					vhandles[i] = r_it->v0;  
					Self::mesh().property( idx_, r_it->v0) = i;  
					++i; 
				}


				// base faces
				typename Mesh::ConstFaceIter f_it  = Self::mesh().faces_begin(), 
					f_end = Self::mesh().faces_end();
				for (; f_it != f_end; ++f_it) 
					if (!Self::mesh().status(f_it).deleted()) 
						++n_base_faces;

				// ---------------------------------------- write progressive mesh

				std::ofstream out( _ofname.c_str(), std::ios::binary );

				if (!out)
					return false;   

				// always use little endian byte ordering
				bool swap = Endian::local() != Endian::LSB;

				// write header
				out << "ProgMesh";
				IO::store( out, n_base_vertices, swap );
				IO::store( out, n_base_faces   , swap );
				IO::store( out, pmi_.size()    , swap );

				Vec3f p;

				// write base vertices
				for (i=0; i<n_base_vertices; ++i)
				{
					assert (!Self::mesh().status(vhandles[i]).deleted());
					p  = vector_cast< Vec3f >( Self::mesh().point(vhandles[i]) );

					IO::store( out, p, swap );
				}


				// write base faces
				for (f_it=Self::mesh().faces_begin(); f_it != f_end; ++f_it)  
				{
					if (!Self::mesh().status(f_it).deleted()) 
					{
						typename Mesh::ConstFaceVertexIter fv_it(Self::mesh(), f_it.handle());

						IO::store( out, Self::mesh().property( idx_,   fv_it ) );
						IO::store( out, Self::mesh().property( idx_, ++fv_it ) );
						IO::store( out, Self::mesh().property( idx_, ++fv_it ) );
					}
				}


				// write detail info
				for (r_it=pmi_.rbegin(); r_it!=r_end; ++r_it)  
				{ 
					// store v0.pos, v1.idx, vl.idx, vr.idx
					IO::store( out, vector_cast<Vec3f>(Self::mesh().point(r_it->v0)));
					IO::store( out, Self::mesh().property( idx_, r_it->v1 ) );
					IO::store( out, 
						r_it->vl.is_valid() ? Self::mesh().property(idx_, r_it->vl) : -1 );
					IO::store( out, 
						r_it->vr.is_valid() ? Self::mesh().property(idx_, r_it->vr) : -1 );
				}

				return true;
		}



		//=============================================================================
	} // END_NS_DECIMATER
} // END_NS_OPENMESH
//=============================================================================

